package com.yc.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Company 源辰信息
 *
 * @author navy
 * @date 2024/7/30
 * Email haijunzhou@hnit.edu.cn
 */
public class Junit {

    public static void main(String[] args) {
        testObject(new MathBizTest());
    }

    public static void testObject(Object tester) {
        // 收集方法
        List<Method> testMethodList = new ArrayList<>();
        List<Method> beforeMethodList = new ArrayList<>();
        List<Method> afterMethodList = new ArrayList<>();

        for (Method method : tester.getClass().getDeclaredMethods()) {
            if (method.getAnnotation(Before.class) != null) {
                beforeMethodList.add(method);
            } else if (method.getAnnotation(After.class) != null) {
                afterMethodList.add(method);
            } else if (method.getAnnotation(Test.class) != null) {
                testMethodList.add(method);
            }
        }

        // 测试方法排序
        testMethodList.sort((a, b) -> {
            // a,b 都是 method
            Test testa = a.getAnnotation(Test.class);
            Test testb = b.getAnnotation(Test.class);
            return testa.value() - testb.value();  // 正数=>升序
        });

        // 执行测试
        for (Method method : testMethodList) {

            for (Method beforeMethod : beforeMethodList) {
                try {
                    beforeMethod.invoke(tester);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }

            // junit 要求测试方法不能有任何参数, 且是共有的
            try {
                method.invoke(tester);
                System.out.println(method + "测试正确!");
            } catch (IllegalAccessException e) {
                System.out.println("======== 不会出现该异常 =========");
            } catch (InvocationTargetException e) {
                // 业务方法内部出现的异常, 都会被该异常所封装,
                Throwable cause = e.getCause();
                // cause 才是业务异常
                System.out.println("cause = " + cause);

                if (cause instanceof AssertException) {
                    System.out.println(method + "测试错误!");
                } else {
                    System.out.println(method + "测试异常!");
                }
            }

            for (Method afterMethod : afterMethodList) {
                try {
                    afterMethod.invoke(tester);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
    int value();
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Before {
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface After {
}

class Assert {

    static void assertEquals(Object exp, Object act) {
        if (!act.equals(exp)) {
            // 断言异常
            throw new AssertException(String.format("期望值是%s, 实际值是%s", exp, act));
        }
    }
}

class AssertException extends RuntimeException {
    public AssertException(String message) {
        super(message);
    }
}


//////////////////////////////////////////////////
class MathBiz {
    // 正常业务方法
    public int add(int a, int b) {
        return a + b;
    }

    // 正常业务方法
    public int div(int a, int b) {
        return a / b;
    }

    // 异常业务方法
    public int sub(int a, int b) {
        int i = 1 / 0;
        return a - b;
    }

    // 错误业务方法
    public int mul(int a, int b) {
        return a * b + 100;
    }

    // 错误业务方法
    public int pow(int a) {
        return a * a + 200;
    }
}

class MathBizTest {
    MathBiz biz;

    @Test(1)
    public void test1() {
        System.out.println("-------- test1 --------");
        int res = biz.add(1, 1);
        Assert.assertEquals(2, res);
    }

    @Test(3)
    public void test2() {
        System.out.println("-------- test2 --------");
        int res = biz.sub(1, 1);
        Assert.assertEquals(0, res);
    }

    @Test(5)
    public void test3() {
        System.out.println("-------- test3 --------");
        int res = biz.mul(1, 1);
        Assert.assertEquals(1, res);
    }

    @Test(2)
    public void test4() {
        System.out.println("-------- test4 --------");
        int res = biz.div(1, 1);
        Assert.assertEquals(1, res);
    }

    @Test(4)
    public void test5() {
        System.out.println("-------- test5 --------");
        int res = biz.pow(2);
        Assert.assertEquals(4, res);
    }

    // 每个测试方法执行前执行的方法
    @Before
    public void before() {
        System.out.println("======== before =======");
        biz = new MathBiz();
    }

    // 每个测试方法执行后执行的方法
    @After
    public void after() {
        System.out.println("======== after =======");
        biz = null;
    }
}